/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.ac.iie.di.ban.news.server.util;

import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.log4j.Logger;

/**
 *
 * @author zwlin
 */
public class HostInfoKeeper {

    private static Logger logger = Logger.getLogger(HostInfoKeeper.class);

    private long delta;

    public HostInfoKeeper(long maxDelaySecond) {
        delta = maxDelaySecond * 1000;
        testHosts = new ConcurrentHashMap<>();
        testLock = new ReentrantReadWriteLock();
        testHostLines = "";
        onlineHosts = new ConcurrentHashMap<>();
        onlineLock = new ReentrantReadWriteLock();
        onlineHostLines = "";
        isActivated = false;
        checkTimer = new Timer("HostInfoCheckTimer");
    }

    public void start() {
        checkTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                check();
            }
        }, 0, delta / 2);
        isActivated = true;
    }

    public void stop() {
        isActivated = false;
        checkTimer.cancel();
    }

    //tag
    private boolean isActivated;
    //test and online
    private final ConcurrentHashMap<String, Long> testHosts;
    private final ReentrantReadWriteLock testLock;
    private String testHostLines;
    private final ConcurrentHashMap<String, Long> onlineHosts;
    private final ReentrantReadWriteLock onlineLock;
    private String onlineHostLines;

    //check timer
    private Timer checkTimer;

    public void regTestHost(String host) {
        if (!isActivated) {
            return;
        }
        testLock.writeLock().lock();
        try {
            if (!testHosts.containsKey(host)) {
                if (testHostLines.length() > 0) {
                    testHostLines += "\n";
                }
                testHostLines += host;
            }
            testHosts.put(host, System.currentTimeMillis());
        } finally {
            testLock.writeLock().unlock();
        }
        logger.debug("testHostLines: " + testHostLines);
    }

    public void regOnlineHost(String host) {
        if (!isActivated) {
            return;
        }
        onlineLock.writeLock().lock();
        try {
            if (!onlineHosts.containsKey(host)) {
                if (onlineHostLines.length() > 0) {
                    onlineHostLines += "\n";
                }
                onlineHostLines += host;
            }
            onlineHosts.put(host, System.currentTimeMillis());
        } finally {
            onlineLock.writeLock().unlock();
        }
        logger.debug("onlineHostLines: " + onlineHostLines);
    }

    private void check() {
        if (!isActivated) {
            return;
        }
        //minimum time not delete
        long min = System.currentTimeMillis() - delta;
        //if need to rebuild hostline,no remove means no need
        boolean needRebuild = false;
        //hostline builder
        StringBuilder hostline = new StringBuilder();
        //for test hosts
        testLock.writeLock().lock();
        try {
            //get iterator
            Iterator<Map.Entry<String, Long>> itr = testHosts.entrySet().iterator();
            //each host entry
            while (itr.hasNext()) {
                Map.Entry<String, Long> h = itr.next();
                //last reg time less than min time, remove host and need rebuild
                if (h.getValue() < min) {
                    needRebuild = true;
                    itr.remove();
                }
            }
            //rebuild host line if need
            if (needRebuild) {
                for (String host : testHosts.keySet()) {
                    if (hostline.length() > 0) {
                        hostline.append("\n");
                    }
                    hostline.append(host);
                }
                testHostLines = hostline.toString();
            }
        } finally {
            testLock.writeLock().unlock();
        }
        logger.debug("testHostLines: " + testHostLines);
        //reset rebuild tag and host line builder
        needRebuild = false;
        hostline.delete(0, hostline.length());
        //for online hosts
        onlineLock.writeLock().lock();
        try {
            Iterator<Map.Entry<String, Long>> itr = onlineHosts.entrySet().iterator();
            while (itr.hasNext()) {
                Map.Entry<String, Long> h = itr.next();
                if (h.getValue() < min) {
                    needRebuild = true;
                    itr.remove();
                }
            }
            if (needRebuild) {
                for (String host : onlineHosts.keySet()) {
                    if (hostline.length() > 0) {
                        hostline.append("\n");
                    }
                    hostline.append(host);
                }
                onlineHostLines = hostline.toString();
            }
        } finally {
            onlineLock.writeLock().unlock();
        }
        logger.debug("onlineHostLines: " + onlineHostLines);
    }

    public String getTestHostLines() {
        if (!isActivated) {
            return null;
        }
        return testHostLines;
    }

    public String getOnlineHostLines() {
        if (!isActivated) {
            return null;
        }
        return onlineHostLines;
    }
}
